package com.zenithmind.user.pojo.domain.valueobject;

import lombok.Value;
import io.swagger.v3.oas.annotations.media.Schema;

/**
 * 存储配额值对象
 * 遵循单一职责原则：只负责存储配额管理
 * 遵循封装原则：不可变对象，业务逻辑封装
 */
@Value
@Schema(description = "存储配额")
public class StorageQuota {
    
    private static final long DEFAULT_LIMIT = 1024L * 1024L * 1024L; // 1GB
    private static final long UNLIMITED = -1L;

    @Schema(description = "已使用存储空间（字节）")
    long used;

    @Schema(description = "存储空间限制（字节，-1表示无限制）")
    long limit;

    /**
     * 创建默认配额
     */
    public static StorageQuota defaultQuota() {
        return new StorageQuota(0L, DEFAULT_LIMIT);
    }

    /**
     * 创建无限制配额
     */
    public static StorageQuota unlimited() {
        return new StorageQuota(0L, UNLIMITED);
    }

    /**
     * 创建自定义配额
     */
    public static StorageQuota create(long limit) {
        if (limit < 0 && limit != UNLIMITED) {
            throw new IllegalArgumentException("存储限制必须为正数或-1（无限制）");
        }
        return new StorageQuota(0L, limit);
    }

    /**
     * 创建带使用量的配额
     */
    public static StorageQuota create(long used, long limit) {
        if (used < 0) {
            throw new IllegalArgumentException("已使用存储空间不能为负数");
        }
        if (limit < 0 && limit != UNLIMITED) {
            throw new IllegalArgumentException("存储限制必须为正数或-1（无限制）");
        }
        if (limit != UNLIMITED && used > limit) {
            throw new IllegalArgumentException("已使用存储空间不能超过限制");
        }
        return new StorageQuota(used, limit);
    }

    /**
     * 更新使用量
     */
    public StorageQuota updateUsed(long deltaSize) {
        long newUsed = used + deltaSize;
        
        // 检查新的使用量是否有效
        if (newUsed < 0) {
            throw new IllegalArgumentException("存储使用量不能为负数");
        }
        
        // 检查是否超过限制
        if (limit != UNLIMITED && newUsed > limit) {
            return null; // 返回null表示操作失败
        }
        
        return new StorageQuota(newUsed, limit);
    }

    /**
     * 设置新的限制
     */
    public StorageQuota withLimit(long newLimit) {
        if (newLimit < 0 && newLimit != UNLIMITED) {
            throw new IllegalArgumentException("存储限制必须为正数或-1（无限制）");
        }
        if (newLimit != UNLIMITED && used > newLimit) {
            throw new IllegalArgumentException("新限制不能小于当前使用量");
        }
        return new StorageQuota(used, newLimit);
    }

    /**
     * 重置使用量
     */
    public StorageQuota reset() {
        return new StorageQuota(0L, limit);
    }

    /**
     * 检查是否可以使用指定大小的存储空间
     */
    public boolean canUse(long size) {
        if (size < 0) {
            return false;
        }
        if (limit == UNLIMITED) {
            return true;
        }
        return used + size <= limit;
    }

    /**
     * 获取剩余空间
     */
    public long getRemaining() {
        if (limit == UNLIMITED) {
            return Long.MAX_VALUE;
        }
        return Math.max(0, limit - used);
    }

    /**
     * 获取使用率（0-100）
     */
    public double getUsagePercentage() {
        if (limit == UNLIMITED || limit == 0) {
            return 0.0;
        }
        return (double) used / limit * 100.0;
    }

    /**
     * 检查是否无限制
     */
    public boolean isUnlimited() {
        return limit == UNLIMITED;
    }

    /**
     * 检查是否已满
     */
    public boolean isFull() {
        if (limit == UNLIMITED) {
            return false;
        }
        return used >= limit;
    }

    /**
     * 检查是否接近满（使用率超过90%）
     */
    public boolean isNearFull() {
        return getUsagePercentage() > 90.0;
    }

    /**
     * 格式化显示大小
     */
    public String formatUsed() {
        return formatBytes(used);
    }

    /**
     * 格式化显示限制
     */
    public String formatLimit() {
        if (limit == UNLIMITED) {
            return "无限制";
        }
        return formatBytes(limit);
    }

    /**
     * 格式化显示配额信息
     */
    public String formatQuota() {
        return formatUsed() + " / " + formatLimit();
    }

    /**
     * 格式化字节大小
     */
    private String formatBytes(long bytes) {
        if (bytes < 1024) {
            return bytes + " B";
        }
        int exp = (int) (Math.log(bytes) / Math.log(1024));
        String pre = "KMGTPE".charAt(exp - 1) + "";
        return String.format("%.1f %sB", bytes / Math.pow(1024, exp), pre);
    }
}
